from datetime import datetime, time

from django.core.handlers.exception import logger
from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import serializers

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
from users.models import Address


class CartSKUSerializer(serializers.ModelSerializer):
    """购物车商品数据序列化器"""
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """订单结算数据序列化器"""
    # max_digits数字允许的最大位数(整数部分+小数部分) decimal_places小数的最大位数
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    # CartSKUSerializer这个序列化器功能实际上和CartSKUSerializer序列化器基本一样,可直接采用CartSKUSerializer
    skus = CartSKUSerializer(many=True)


class SaveOrderSerializer(serializers.Serializer):  # 这里也可以继承自ModelSerializer,那么就不需要定义字段,但是需要给字段添加属性以及重新定义create方法
    order_id = serializers.CharField(read_only=True)
    address = serializers.IntegerField(write_only=True, required=True)
    pay_method = serializers.IntegerField(write_only=True, required=True)

    # 验证方法
    def validate_address(self, value):
        count = Address.objects.filter(pk=value).count()
        if count <= 0:
            raise serializers.ValidationError('无效的收货地址')
        return value

    def validate_pay_method(self, value):
        if value not in [1,2]:
            raise serializers.ValidationError('无效的付款方式')
        return value

    def create(self, validated_data):
        # 启用事务
        with transaction.atomic():
            # 开启事务
            sid = transaction.savepoint()

            try:
                # 获取验证的数据
                address = validated_data.get('address')
                pay_method = validated_data.get('pay_method')
                # 获取用户编号
                user_id = self.context['request'].user.id
                # 生成主键
                order_id = datetime.now().strftime('%Y%m%d%H%M%S') + '%09d' % user_id
                # 创建订单对象
                total_count = 0
                total_amount = 0
                order = OrderInfo.objects.create(
                    order_id = order_id,
                    user_id = user_id,
                    address_id = address,
                    total_count = 0,
                    total_amount = 0,
                    freight = 10,
                    pay_method = pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                )
                # 读取redis中选中的商品编号/数量
                redis_conn = get_redis_connection('cart')
                # 读取hash中的商品/数量,并转换成int类型{sku_id: count, sku_id:count,...}
                cart_redis = redis_conn.hgetall('cart_%d' % user_id)
                cart_dict = {}
                for sku_id, count in cart_redis.items():
                    cart_dict[int(sku_id)] = int(count)
                # 读取set中选中的商品编号,转换成int类型
                cart_selected = redis_conn.smembers('cart_selected_%d' % user_id)
                sku_ids = [int(sku_id) for sku_id in cart_selected]
                # 查询购物车中选中的商品对象
                skus = SKU.objects.filter(pk__in=sku_ids)
                # 遍历
                for sku in skus:
                    # 获取购买数量
                    count = cart_dict[sku.id]
                    # 判断库存
                    if sku.stock < count:
                        transaction.savepoint_rollback(sid)
                        raise serializers.ValidationError('库存不足')

                    # 修改商品的库存量/销量
                    sku.stock -= count
                    sku.sales += count
                    sku.save()

                    """
                    # 修改商品的库存量/销量
                    # 使用乐观锁修改库存
                    # time.sleep(5)  # 用于演示并发下单
                    stock = sku.stock - count
                    sales = sku.sales + count
                    result = SKU.objects.filter(pk=sku.id, stock=sku.stock).update(stock=stock, sales=sales)  # 如果修改成功,则返回1否则返回0.
                    if result <= 0:
                        transaction.savepoint_rollback(sid)
                        raise serializers.ValidationError('当前购买人数太多,请稍后重试')
                    """

                    # 创建订单商品对象
                    OrderGoods.objects.create(
                        order_id = order_id,
                        sku_id = sku.id,
                        count = count,
                        price = sku.price
                    )
                    # 计算总数量/总金额
                    total_count += count
                    total_amount += count*sku.price
                # 修改订单的总数量/总金额
                order.total_count = total_count
                order.total_amount = total_amount + order.freight
                order.save()
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(sid)
                raise

            # 提交事务
            transaction.savepoint_commit(sid)

            # 删除redis中选中的商品
            pl = redis_conn.pipeline()
            redis_conn.hdel('cart_%d' % user_id, *sku_ids)
            redis_conn.srem('cart_selected_%d' % user_id, *sku_ids)
            pl.execute()

            # 返回新建的订单对象
            return order
